; Uppercase symbols are memory addresses and symbol variables, lowercase symbols points to labels

; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; Initialize sound engine memory with track data
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
sound_init:
		asl
		tay 
		lda audio_track_header_pointer_table,y ; Table is in data.s
		sta !AUDIO_CURRENT_TRACK_AND_STREAM_POINTER
		lda audio_track_header_pointer_table+1,y ; Table is in data.s
		sta !AUDIO_CURRENT_TRACK_AND_STREAM_POINTER+1
		;  Begin loop to populate memory with track data
		ldy #$00 ; data index
		ldx #$ff ; channel index:  gets incremented to zero at the beginning of the loop
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; Populate sound engine memory with track data
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	.next_channel:
		inx
; First byte in track table 
		lda (!AUDIO_CURRENT_TRACK_AND_STREAM_POINTER), y ; Channel to send data at
		cmp #$ff ; end of header byte value
		beq .initialization_done		
		sta !AUDIO_CHANNEL, x
		iny
; Next byte in track table 
		lda (!AUDIO_CURRENT_TRACK_AND_STREAM_POINTER), y ; Initial Duty/Decay/Volume
		sta !AUDIO_VOL_DUTY, x
		iny
; Next byte in track table 
		lda (!AUDIO_CURRENT_TRACK_AND_STREAM_POINTER), y ; Initial volume envelope stream
		sta !AUDIO_STREAM_VOLUME_ENVELOPE_SET, x
		iny
; Next byte in track table 
		lda (!AUDIO_CURRENT_TRACK_AND_STREAM_POINTER), y ; Initial Tempo
		sta !AUDIO_STREAM_TEMPO, x
		iny
; Next two bytes in track table 
		lda (!AUDIO_CURRENT_TRACK_AND_STREAM_POINTER), y ; Pointer to stream data address
		sta !AUDIO_STREAM_POINTER_LO, x
		iny
		lda (!AUDIO_CURRENT_TRACK_AND_STREAM_POINTER), y 
		sta !AUDIO_STREAM_POINTER_HI, x
		iny
		; Global channnel initialization
		lda #$ff
		sta !AUDIO_STREAM_TICKER_TOTAL, x
		lda #$01
		sta !AUDIO_STREAM_NOTE_LENGTH_COUNTER, x
		lda #$00
		sta !AUDIO_STREAM_VOLUME_ENVELOPE_INDEX, x
		lda #%00000001 ; Stream status = ON
		sta !AUDIO_STREAM_STATUS, x
		jmp .next_channel
	.initialization_done:
		lda #%00001111 ; Activate NES APU channels
		sta $4015
		lda #%10111111 ; 
		sta $4000
		rts

; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; Play a sound engine tick
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
sound_play:
		ldx #$00
	-:;Check if the channel is turned on
		lda !AUDIO_STREAM_STATUS, x ; Stream status
		and #%00000001
		beq advance_to_next_stream ; Jump to next stream if 0

		lda !AUDIO_STREAM_TICKER_TOTAL, x
		clc
		adc !AUDIO_STREAM_TEMPO, x
		sta !AUDIO_STREAM_TICKER_TOTAL, x
		bcc advance_to_next_stream ; Jump to next stream while ticker total differs from rolling over

		dec !AUDIO_STREAM_NOTE_LENGTH_COUNTER, x
		bne advance_to_next_stream ; Jump to next stream if stream note differs from being of value zero
		lda !AUDIO_STREAM_NOTE_LENGTH, x
		sta !AUDIO_STREAM_NOTE_LENGTH_COUNTER, x

		jmp fetch_byte_from_audio_stream


	set_audio_processing_unit:
		lda !AUDIO_CHANNEL, x
		asl
		asl
		tay
		lda !AUDIO_VOL_DUTY, x
		sta $4000, y
		lda !AUDIO_NOTE_LO, x
		sta $4002, y
		lda !AUDIO_NOTE_HI, x
		sta $4003, y

		lda !AUDIO_CHANNEL, x
		cmp !RP2A0X_TRI_CHANNEL
		bcs advance_to_next_stream
		lda #$08
		sta $4001, y

	advance_to_next_stream:
		inc !AUDIO_STREAM_VOLUME_ENVELOPE_INDEX, x
		inx
		cpx #$04; number of streams
		bne -
		rts ; Done

	fetch_byte_from_audio_stream:
		; Fetch byte from stream
		lda !AUDIO_STREAM_POINTER_LO, x
		sta !AUDIO_CURRENT_TRACK_AND_STREAM_POINTER
		lda !AUDIO_STREAM_POINTER_HI, x
		sta !AUDIO_CURRENT_TRACK_AND_STREAM_POINTER+1
		ldy #$00
	--:
		lda (!AUDIO_CURRENT_TRACK_AND_STREAM_POINTER), y

		bmi ++ ; Branch if the data is a command
		cmp #$60
		bcs + ; Branch if the data is a note length
		; If data is a note:
		asl
		sty !AUDIO_TEMPORAL_DATA
		tay
		lda frequency_table, y
		sta !AUDIO_NOTE_LO, x
		lda frequency_table+1, y
		sta !AUDIO_NOTE_HI, x
		ldy !AUDIO_TEMPORAL_DATA
		lda #$00 
		sta !AUDIO_STREAM_VOLUME_ENVELOPE_INDEX, x
		jmp +++ ; Done
	+: ; If data is a note length
		and #%00011111 ; make note length range index start from zero
		clc
		adc #$01
		sta !AUDIO_STREAM_NOTE_LENGTH, x
		sta !AUDIO_STREAM_NOTE_LENGTH_COUNTER, x
		iny
		jmp --
	++: ; If data is a command
		and #%01111111
		asl
		sty !AUDIO_TEMPORAL_DATA
		tay
		lda track_effect_jump_table+1,y
		sta !AUDIO_TEMPORAL_DATA+1
		lda track_effect_jump_table,y
		ldy !AUDIO_TEMPORAL_DATA
		sta !AUDIO_TEMPORAL_DATA
		jmp ($00!AUDIO_TEMPORAL_DATA)

; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; Sound engine track effect implementation
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; End of stream data effect, loops back to previously set loop point or stops track
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	end_of_stream_data_effect:
		;lda !AUDIO_STREAM_STATUS, x
		;and #%11111110
		;sta !AUDIO_STREAM_STATUS, x
		; If loop point has been set, jump back to it (unimplemented)
		lda !AUDIO_STREAM_LOOP_LO, x
		sta !AUDIO_STREAM_POINTER_LO, x
		lda !AUDIO_STREAM_LOOP_HI, x
		sta !AUDIO_STREAM_POINTER_HI, x
		jmp fetch_byte_from_audio_stream
	
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
; Rest effect, produces silence for the duration of current note length set
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	rest_effect:
		lda !AUDIO_CHANNEL, x
		asl
		asl
		sty !AUDIO_TEMPORAL_DATA
		tay
		cpy #$08 ; If triangle channel
		beq ++
		lda #$30 ; Silence
		bpl .write_rest_to_port
		++: ; If triangle channel
		lda #$80 ; Silence value for triangle
		.write_rest_to_port:
		sta $4000, y
		ldy !AUDIO_TEMPORAL_DATA
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	tie_effect: ; Used by TIE command too
		jsr update_audio_pointer
		jmp advance_to_next_stream
; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	loop_effect:
		jsr update_audio_pointer
		lda !AUDIO_STREAM_POINTER_LO, x
		sta !AUDIO_STREAM_LOOP_LO, x
		lda !AUDIO_STREAM_POINTER_HI, x
		sta !AUDIO_STREAM_LOOP_HI, x
		jmp advance_to_next_stream
		; End of effects


	+++: ; Done, update pointer
		jsr update_audio_pointer
		jmp set_audio_processing_unit

	update_audio_pointer:
		iny
		tya
		clc
		adc !AUDIO_STREAM_POINTER_LO, x
		sta !AUDIO_STREAM_POINTER_LO, x
		bcc +
		inc !AUDIO_STREAM_POINTER_HI, x
		+:
		rts